package com.afalon.cloud;

import java.util.List;
import java.util.Map;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import com.afalon.cloud.contracts.system.User;

public class Session {

	final static String User = "User";
	final static String AuthHeaderName = "Authorization";
	final static String AuthDigestHeaderName = "WWW-Authenticate";
	
	public static boolean Authenticated(HttpServletRequest request)
	{
		return ValidUserSession(request) || AuthenticateUser(request);
	}
	
	private static boolean ValidUserSession(HttpServletRequest request)
	{
		return request.getSession().getAttribute(User) != null ? true : false;
	}

	private static boolean AuthenticateUser(HttpServletRequest request)
	{
		
		String requestUrl = request.getRequestURL().toString() + (request.getQueryString()==null ? "" : "?" + request.getQueryString());
		String authHeader = request.getHeader(AuthHeaderName);
		
		// Start Digest Authentication
		 
//		if(!StringExtensions.IsNullOrEmpty(authHeader) && authHeader.startsWith("Digest"))
//		{
//			String a = "a";
//		}
		
		// End Digest Authentication
		
		
		if (StringExtensions.IsNullOrEmpty(authHeader))
		{
			//throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).entity("Invalid Authorisation Header.").type(MediaType.TEXT_PLAIN).build());		
			// Start Digest Authentication
			String AuthDigestHeaderValue = "Digest realm=\"afalon\", qop=\"auth\", nonce=\"" + StringExtensions.GenerateNonce() + "\", opaque=\"" + StringExtensions.GenerateNonce() + "\"";
			
			throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).entity("Invalid Authorisation Header.").type(MediaType.TEXT_PLAIN).header(AuthDigestHeaderName, AuthDigestHeaderValue).build());
			
			// digest request
			// Digest username="kevin", realm="afalon", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", uri="/rest/links/", response="604d2c33c24767e2b9c229bcf805bcf4", opaque="5ccc069c403ebaf9f0171e9517f40e41", qop=auth, nc=00000001, cnonce="2170476e9e804b5b"
			
			// End Digest Authentication
		}
		else
		{
			if(!StringExtensions.IsNullOrEmpty(authHeader) && authHeader.startsWith("Digest"))
			{
				// HA1 = MD5(username:realm:password)
				// HA2 = MD5(method:URI)
				// resp = MD5(HA1:nonce:nonceCount:clientNonce:"auth":HA2)
				
				Map<String, String> digestParams = MapExtensions.parseMap(authHeader.replace("Digest ", ""));
				
				PersistenceManager pm = PMF.get().getPersistenceManager();
                
        	    Query query = pm.newQuery(User.class);
        	    query.setFilter("logon == logonParam");

        	    query.declareParameters("String logonParam");

        	    try { // Check LogOn is valid

					List<User> users = (List<User>)query.execute(digestParams.get("username"));
        	        if (users.iterator().hasNext()) {
                    	User user = users.get(0);
                    	
                    	String ha1 = StringExtensions.GenerateMD5(digestParams.get("username") + ":" + digestParams.get("realm") + ":" + user.getPassword());
                    	String ha2 = StringExtensions.GenerateMD5(request.getMethod() + ":" + digestParams.get("uri"));
                    	String resp = StringExtensions.GenerateMD5(ha1 + ":" + digestParams.get("nonce") + ":" + digestParams.get("nc") + ":" + digestParams.get("cnonce") + ":" + digestParams.get("qop") + ":" + ha2);
                    	if (digestParams.get("response").equals(resp))
                    	{
                    		request.getSession().setAttribute(User, user);
                    		return true;
                    	}
                    	else
                    	{
                    		throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).entity("Invalid Password.").type(MediaType.TEXT_PLAIN).build());
                    	}	
        	        } else {
        	        	throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).entity("Invalid Log On.").type(MediaType.TEXT_PLAIN).build());
        	        }
        	    } finally {
        	        query.closeAll();
        	    }
				
			}
			else
			{
				// using afalon auth
				String[] authParts = authHeader.split(":");
				if (authParts.length == 2)
				{
					String logOn = authParts[0];
	                String hash = authParts[1];
	                
	                PersistenceManager pm = PMF.get().getPersistenceManager();
	                
	        	    Query query = pm.newQuery(User.class);
	        	    query.setFilter("logon == logonParam");
	
	        	    query.declareParameters("String logonParam");
	
	        	    try { // Check LogOn is valid
	        	        @SuppressWarnings("unchecked")
						List<User> users = (List<User>)query.execute(logOn);
	        	        if (users.iterator().hasNext()) {
	                    	User user = users.get(0);
	                    	if (StringExtensions.ValidateKeyedMD5(hash, requestUrl, user.getPassword())) 
	                    	{
	                    		// LoadUserSession
	                    		request.getSession().setAttribute(User, user);
	                    		return true;
	                    	}
	                    	else
	                    	{
	                    		throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).entity("Invalid Password.").type(MediaType.TEXT_PLAIN).build());
	                    	}	
	        	        } else {
	        	        	throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).entity("Invalid Log On.").type(MediaType.TEXT_PLAIN).build());
	        	        }
	        	    } finally {
	        	        query.closeAll();
	        	    }
				}
				else
				{
					throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).entity("Invalid Authorisation Header.").type(MediaType.TEXT_PLAIN).build());
				}
			}
			
			
		}
		
		
		//throw new WebApplicationException(Response.Status.SERVICE_UNAVAILABLE);
		
		
		
	}
	

	
	
}
